<?php

namespace App\Models\Trip\TripOrderCosts\Repositories;

use App\Models\Orders\Repositories\Interfaces\OrdersInterface;
use App\Models\Trip\TripOrderCosts\Repositories\Interfaces\TripOrderCostsRepositoryInterface;
use App\Models\Trip\TripOrderCosts\TripOrderCost;
use App\Trip\Repository\BaseRepository;
use Exception;
use Illuminate\Support\Collection;

class TripOrderCostsRepository extends BaseRepository implements TripOrderCostsRepositoryInterface
{

    public function __construct(TripOrderCost $model)
    {
        parent::__construct($model);
    }

    public function listByUserTrip(string $user_id, string $trip_id): Collection
    {
        return $this->findBy([
            'user_id' => $user_id,
            'trip_id' => $trip_id,
        ]);

    }

    /**
     * 批量添加花费明细
     * @param OrdersInterface $order
     * @param array           $datas
     * @return bool
     * @throws Exception
     */
    public function addMore(OrdersInterface $order, array $datas): bool
    {
        $costs = [];
        foreach ($datas['details'] as $key => $cost) {
            $pay_sn = $cost['pay_sn'] ?? '';
            if ($cost_info = $this->findOneByOrderAndTypeName($order, $cost['type'], $cost['name'], $pay_sn)) {
                // 可能涉及到更新
                if (!$cost_info->pay_sn && $pay_sn) {
                    $this->update(['pay_sn' => $pay_sn], $cost_info);
                }
                continue;
            }
            $costs[$key] = [
                "user_id"     => $order->getUserId(),
                "order_sn"    => $order->getOrderSn(),
                "trip_id"     => $order->getTripId(),
                "trip_type"   => $order->getTripType(),
                "trip_no"     => $order->getTripNo(),
                "type"        => $cost['type'],
                "parent_type" => $cost['parent_type'],
                "name"        => $cost['name'],
                "detail"      => $cost['detail'] ?? "",
                "price"       => $cost['price'],
                "count"       => $cost['count'],
                "pay_sn"      => $cost['pay_sn'] ?? '',
                "created_at"  => $order->getCreatedAt(),
                "updated_at"  => $order->getCreatedAt(),
            ];
        }
        if (empty($costs)) {
            return true;
        }
        return $this->model->insert($costs);
    }

    /**
     * @param OrdersInterface $order
     * @param int             $type
     * @param string          $name
     * @param string          $pay_sn
     * @return TripOrderCost|null
     * @throws Exception
     */
    public function findOneByOrderAndTypeName(OrdersInterface $order, int $type, string $name, string $pay_sn = ''): ?TripOrderCost
    {

        $where = [
            "user_id"   => $order->getUserId(),
            "order_sn"  => $order->getOrderSn(),
            "trip_id"   => $order->getTripId(),
            "trip_type" => $order->getTripType(),
            "trip_no"   => $order->getTripNo(),
            "type"      => $type,
            "name"      => $name,
        ];

        if (TripOrderCost::mayHasMoreRecord($type)) {
            if (!$pay_sn) {
                throw new Exception("类型 {$type} 缺少参数,pay_sn");
            }

            $where['pay_sn'] = $pay_sn;
        }

        return $this->findOneBy($where);
    }

    public function listByOrder(OrdersInterface $order, array $condition = [], array $excepts = []): Collection
    {
        $where = [
            'user_id'  => $order->getUserId(),
            'trip_id'  => $order->getTripId(),
            'order_sn' => $order->getOrderSn(),
        ];

        if (!empty($condition)) {
            unset($condition['user_id'], $condition['trip_id'], $condition['order_sn']);
            $where = array_merge($where, $condition);
        }

        $query = $this->model->where($where);
        if (!empty($excepts)) {
            if (isset($excepts['type'])) {
                if (is_array($excepts['type'])) {
                    $query = $query->whereNotIn('type', $excepts['type']);
                } else {
                    $query = $query->where('type', '!=', $excepts['type']);
                }
            }

        }
        return $query->get();
    }

    /**
     * 更新指定类型名称的成本
     *
     * @param OrdersInterface $order
     * @param array           $cost
     * @return bool
     * @throws Exception
     */
    public function addByNewOrderTicketCost(OrdersInterface $order, array $cost): bool
    {
        // 未支付的不需要更新
        $pay_sn   = $cost['pay_sn'] ?? '';
        $new_type = $cost['type'] ?? '';
        if (!$pay_sn) {
            return true;
        }

        $before_order_costs      = $this->getOrderPassengersTicketCosts($order);
        $before_order_cost_price = $before_order_costs->sum(fn($detail) => $detail['count'] * $detail['price']);
        $new_price               = $cost['new_price'];
        // 如果价格没变直接跳过
        if ($before_order_cost_price == $new_price) {
            return true;
        }

        $price = $new_price - $before_order_cost_price;
        // 已新增的编辑差价记录
        if ($new_type == TripOrderCost::COST_TYPE_SNAP_EDIT_TICKET_PRICE_DIFF) {
            $this->addOne($order, [
                "parent_type" => TripOrderCost::COST_TYPE_TICKET,
                "type"        => $new_type,
                "name"        => TripOrderCost::COST_TYPE_DESC[$new_type],
                "price"       => $price, // 单价
                "count"       => $cost['count'],
                "pay_sn"      => $pay_sn,
            ]);
            return true;
        } else {
            throw new Exception("不支持的新增, new_type: {$new_type},{$pay_sn}");
        }

    }

    /**
     * 票价相关的成本明细
     * @param OrdersInterface $order
     * @return Collection
     */
    public function getOrderPassengersTicketCosts(OrdersInterface $order): Collection
    {
        return $this->findBy([
            'user_id'     => $order->getUserId(),
            'trip_id'     => $order->getTripId(),
            'order_sn'    => $order->getOrderSn(),
            'parent_type' => TripOrderCost::COST_TYPE_TICKET, // type in COST_TYPE_TICKET  or COST_TYPE_SNAP_EDIT_TICKET_PRICE_DIFF
        ]);
    }

    /**
     * @throws Exception
     */
    public function addOne(OrdersInterface $order, array $data): TripOrderCost
    {
        $pay_sn = $data['pay_sn'] ?? '';
        if ($cost_info = $this->findOneByOrderAndTypeName($order, $data['type'], $data['name'], $pay_sn)) {
            // 可能涉及到更新
            if (!$cost_info->pay_sn && $pay_sn) {
                $this->update(['pay_sn' => $pay_sn], $cost_info);
            }
            return $cost_info;
        }
        $data['user_id']   = $order->getUserId();
        $data['order_sn']  = $order->getOrderSn();
        $data['trip_id']   = $order->getTripId();
        $data['trip_type'] = $order->getTripType();
        $data['trip_no']   = $order->getTripNo();
        return $this->create($data);
    }

    public function updateOne(TripOrderCost $cost, array $data): bool
    {
        return $this->update($data, $cost);
    }

    public function updatePaySnByOrder(OrdersInterface $order, string $pay_sn, array $types = []): bool
    {
        $where = [
            'order_sn'  => $order->getOrderSn(),
            'trip_id'   => $order->getTripId(),
            'trip_type' => $order->getTripType(),
            'user_id'   => $order->getUserId(),
        ];
        return $this->where($where)
                    ->where('pay_sn', '')
                    ->when($types, function ($q) use ($types) {
                        $q->whereIn('type', $types);
                    })
                    ->update([
                        'pay_sn' => $pay_sn,
                    ]);
    }
}